iT邦幫忙

2022 iThome 鐵人賽

DAY 6
0
自我挑戰組

30天演算法解題系列 第 6

Day 06:tournament winner

  • 分享至 

  • xImage
  •  

problem

至少兩支隊伍進行錦標賽,其中每一隊都會跟其他所有的隊伍進行一對一比賽。每場比賽贏的加 3 分,輸的加 0 分,不會有平手的情況。累積總分最高的就是錦標賽的獲勝者,題目保證只會有一隊獲勝。

輸入為兩個陣列 competitions 和 results,competitions 是雙層陣列結構,每個元素是每場比賽的兩個隊伍 (字串),results 的相同應索引位置則是該場比賽的結果。例如 competitions[i] 為 [teamA, teamB],results[i] 若為 1 代表 teamA 獲勝,0 則代表 teamB 獲勝。輸出最終獲勝的隊伍。

sample input:
competitions = [
  ['HTML', 'C#'],
  ['C#', 'Python'],
  ['Python', 'HTML']
]
results = [0, 0, 1]

sample output:
'Python' // 三場比賽獲勝的分別是 C#、Python、Python,所以積分為 C# 3 分,Python 6 分

這題屬於情境描述很囉唆,但實際邏輯不會太複雜。簡單來說步驟是:

  1. 以迴圈遍歷每一場比賽和結果。
  2. 以 hash table 記錄分數。如果獲勝的隊伍有在 hash table 中,將原本的分數加 3,否則以隊伍名稱為 key 加進去且值存為 3。
  3. 從 hash table 中回傳積分最高的隊伍。

如果光看以上步驟,很有可能會迴圈過陣列記錄分數,然後最後再迴圈過一次 hash table 來找出最高分隊伍。但如果可以在第一次迴圈的同時也記錄最高分隊伍,就可以稍微優化一下程式碼。

方法是在一開始先初始化變數 bestTeam = '',代表當前最高分隊伍,並先放在 hash table 中,分數訂為 0,以免出現查找不到的錯誤。接著在每一次為獲勝隊伍計分完之後,比較獲勝隊伍與 bestTeam 的分數,如果前者較高,則更新 bestTeam。如此一來,迴圈跑完也就可以直接回傳累積最高分的 bestTeam。

n 為比賽數目 (competitions/ results 的陣列長度)
time: O(n)

k 為隊伍數目
space: O(k) 因為 hash table 中至多會記錄 k + 1 支隊伍的分數,+ 1 是來自於剛剛提到另外設定的 bestTeam 。

function tournamentWinner(competitions, results) {
  let bestTeam = '';
  const scores = { [bestTeam]: 0 };

  for (let i = 0; i < competitions.length; i++) {
    // 找出每場比賽獲勝隊伍
    const result = results[i];
    const [teamA, teamB] = competitions[i];
    const winner = result === 1 ? teamA : teamB;

    // 獲勝隊伍計分
    if (!(winner in scores)) scores[winner] = 0;
    scores[winner] += 3;

    // 計分後和目前最高分比較
    if (scores[winner] > scores[bestTeam]) {
      bestTeam = winner;
    }
  }
  return bestTeam;
}

無聊的題外話,sample input 之所以會是程式語言的名稱,是因為原文題目的故事情境是有幾個隊伍要進行演算法錦標賽,看哪一隊寫的演算法最快。那就有點好奇,為什麼這種比賽會有隊伍叫 HTML...還是其實隊名就說明了為什麼他們一場都沒贏過...


上一篇
Day 05:non-constructible change
下一篇
Day 07:smallest difference
系列文
30天演算法解題30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言